package com.deanlib.cabinet.ui.view.photo;

import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.common.HttpMethod;
import com.alibaba.sdk.android.oss.model.GeneratePresignedUrlRequest;
import com.alibaba.sdk.android.oss.model.GetObjectRequest;
import com.alibaba.sdk.android.oss.model.GetObjectResult;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.deanlib.cabinet.R;
import com.deanlib.cabinet.base.BaseFragment;
import com.deanlib.cabinet.data.AppDatabase;
import com.deanlib.cabinet.data.db.ResourceCacheDao;
import com.deanlib.cabinet.data.db.ResourceDao;
import com.deanlib.cabinet.data.event.UserStateEvent;
import com.deanlib.cabinet.data.model.Resource;
import com.deanlib.cabinet.data.model.ResourceCache;
import com.deanlib.cabinet.data.network.NetWorkManager;
import com.deanlib.cabinet.data.network.Response;
import com.deanlib.cabinet.data.network.ResponseTransformer;
import com.deanlib.cabinet.data.network.schedulers.SchedulerProvider;
import com.deanlib.cabinet.databinding.FragmentPhotoList3Binding;
import com.deanlib.cabinet.databinding.LayoutMediaContentItemBinding;
import com.deanlib.cabinet.ui.Navigation;
import com.deanlib.cabinet.ui.adapter.MediaGrid2Adapter;
import com.deanlib.cabinet.ui.recyclerview.CommonRecyclerViewAdapter;
import com.deanlib.cabinet.ui.recyclerview.CommonViewHolder;
import com.deanlib.cabinet.ui.recyclerview.OnItemClickListener;
import com.deanlib.cabinet.utils.ConfigManager;
import com.deanlib.cabinet.utils.FileUtilsExt;
import com.deanlib.cabinet.utils.MediaUtilsExt;
import com.deanlib.cabinet.utils.NetworkManagerExt;
import com.deanlib.cabinet.utils.OssManager;
import com.deanlib.cabinet.utils.UserManager;
import com.deanlib.plantern.utils.FileUtils;
import com.deanlib.plantern.utils.FormatUtils;
import com.deanlib.plantern.utils.ImageUtils;
import com.deanlib.plantern.utils.PopupUtils;
import com.elvishew.xlog.XLog;
import com.scwang.smart.refresh.layout.api.RefreshLayout;
import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener;
import com.wanglu.photoviewerlibrary.PhotoViewer;

import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.greenrobot.greendao.query.QueryBuilder;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;

/**
 * Created by Dean on 2023/6/11
 */
public class PhotoList3Fragment extends BaseFragment<FragmentPhotoList3Binding> {

    MediaGrid2Adapter mediaGridAdapter;
    List<Resource> mediaGridDataList;
    GridLayoutManager gridLayoutManager;
    int pageSize = 60;
    //    int pageNum = 1;
    long lastResCreateTime = System.currentTimeMillis();

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void eventUserState(UserStateEvent event) {
        //todo
    }

    @Override
    public void initView() {
        gridLayoutManager = new GridLayoutManager(getContext(), 3);
        binding.rvResources.setLayoutManager(gridLayoutManager);
        mediaGridAdapter = new MediaGrid2Adapter(mediaGridDataList = new ArrayList<>());
        binding.rvResources.setAdapter(mediaGridAdapter);

        /*binding.rvResources.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                if (newState == RecyclerView.SCROLL_STATE_IDLE){
//                    Glide.with(getContext()).resumeRequests();
                    int firstVisiblePosition = gridLayoutManager.findFirstVisibleItemPosition();
                    int lastVisiblePosition = gridLayoutManager.findLastVisibleItemPosition();
                    for (int position = firstVisiblePosition; position <= lastVisiblePosition; position++){
                        CommonViewHolder<LayoutMediaContentItemBinding> holder =
                                (CommonViewHolder<LayoutMediaContentItemBinding>) recyclerView.findViewHolderForAdapterPosition(position);
                        Resource resource = mediaGridDataList.get(position);
                        mediaGridAdapter.loadItem(holder, resource);
                    }
                }else {
//                    Glide.with(getContext()).pauseRequests();
                }
            }
        });*/
        binding.srLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() {
            @Override
            public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
//                pageNum ++;
                if (!mediaGridDataList.isEmpty()) {
                    lastResCreateTime = mediaGridDataList.get(mediaGridDataList.size() - 1).getResCreateTime() - 1;
                } else {
                    lastResCreateTime = System.currentTimeMillis();
                }
                loadData();
            }

            @Override
            public void onRefresh(@NonNull RefreshLayout refreshLayout) {
//                pageNum = 1;
                lastResCreateTime = System.currentTimeMillis();
                mediaGridDataList.clear();
                loadData();
            }
        });

        mediaGridAdapter.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Navigation.toMediaGalleryBrowser(getActivity(), mediaGridDataList.get(position));
            }
        });
    }

    Handler handler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1) {
                toast((String) msg.obj);
            }
        }
    };

    @Override
    public void loadData() {
        Observable<Optional<List<Resource>>> observable = null;
        if (UserManager.getInstance().isLogin() && NetworkManagerExt.isNetworkConn()) {
            XLog.i("请求网络资源");
            //请求网络资源
            observable = NetWorkManager.getRequest().getResourceListByCreateTime(lastResCreateTime, pageSize)
                    .map(new Function<Response<List<Resource>>, Optional<List<Resource>>>() {
                        @Override
                        public Optional<List<Resource>> apply(Response<List<Resource>> listResponse) throws Exception {
                            if (!listResponse.getSuccess()) {
                                ResponseTransformer.handleResponseFail(listResponse);
                                handler.sendMessage(handler.obtainMessage(1, listResponse.getMessage()));
                            }
                            List<Resource> netResourceList = listResponse.getData();
                            XLog.i("请求到网络资源：" + netResourceList.size());
                            //获取本地资源
                            Observable<Optional<List<Resource>>> localResObservable = null;
                            if (!netResourceList.isEmpty()) {
                                long start = netResourceList.get(0).getResCreateTime();
                                if (netResourceList.size() < pageSize) {
                                    //网络数据不够一页了，取本地数据 pageSize条
                                    localResObservable = getLocalResourceListObservable(lastResCreateTime, pageSize);
                                } else {
                                    //网络数据请求到了,再获取本地资源，进行合并
                                    long end = netResourceList.get(netResourceList.size() - 1).getResCreateTime();
                                    localResObservable = getLocalResourceListObservable(start, end);
                                }
                            } else {
                                //网络数据没有了,直接取本地数据 pageSize条
                                localResObservable = getLocalResourceListObservable(lastResCreateTime, pageSize);
                            }

                            List<Resource> finalResourceList = new ArrayList<>();
                            addDisposable(localResObservable.subscribe(optional -> {
                                optional.ifPresent(finalResourceList::addAll);
                            }));
                            if (!netResourceList.isEmpty()) {
                                //本地资源为主，有助于先加载本地资源，节省流量
                                for (Resource netResource : netResourceList) {
                                    boolean find = false;
                                    for (Resource localResource : finalResourceList) {
                                        if (
                                                Objects.equals(localResource.md5, netResource.md5) ||
                                                        Objects.equals(localResource.md5, netResource.newMd5) ||
                                                        Objects.equals(localResource.newMd5, netResource.md5) ||
                                                        Objects.equals(localResource.newMd5, netResource.newMd5)
                                        ) {
                                            find = true;
                                            localResource.shared = netResource.shared;
                                            break;
                                        }
                                    }
                                    if (!find) {
                                        //查询缓存数据
                                        ResourceCache cache = AppDatabase.getDaoSession().getResourceCacheDao().queryBuilder()
                                                .whereOr(ResourceCacheDao.Properties.Md5.eq(netResource.md5),
                                                        ResourceCacheDao.Properties.Md5.eq(netResource.newMd5))
                                                .unique();
                                        XLog.d("md5:" + netResource.md5 + "  newMd5:" + netResource.newMd5 + "  cache:" + cache);
                                        if (cache != null) {
                                            netResource.setLocalPath(cache.getPath());
                                            netResource.setLocalThumbnail(cache.getThumbnailPath());
                                        }
                                        finalResourceList.add(netResource);
                                    }
                                }

                            }
                            Collections.sort(finalResourceList);
                            return Optional.of(finalResourceList);
                        }
                    });
        } else {
            //加载本地资源
//            int offset = (pageNum - 1) * pageSize;
//            if (offset < 0) offset = 0;
            XLog.i("加载本地资源");
            observable = getLocalResourceListObservable(lastResCreateTime, pageSize);
        }

        if (observable == null) return;
        addDisposable(observable.compose(SchedulerProvider.getInstance().applySchedulers())
                .doOnSubscribe(disposable -> loading("", ""))
                .doOnComplete(this::loaded)
                .subscribe(optional -> {
                    if (optional.isPresent() && !optional.get().isEmpty()) {
                        List<Resource> list = optional.get();
                        int position = mediaGridDataList.size();
                        mediaGridDataList.addAll(list);
                        XLog.i("资源总数 : " + mediaGridDataList.size());
                        mediaGridAdapter.notifyItemRangeChanged(position, list.size());
                        finishRefreshLayout(false);
                    } else {
                        finishRefreshLayout(true);
                    }
                }, err -> {
                    PopupUtils.sendToast(err.getMessage());
                    finishRefreshLayout(false);
                }));
    }

    /**
     * 获取本地资源 Observable
     * 翻页
     *
     * @param offset
     * @param limit
     * @return
     */
    private Observable<Optional<List<Resource>>> getLocalResourceListObservable(int offset, int limit) {
        return Observable.create((ObservableOnSubscribe<Optional<List<Resource>>>) emitter -> {
            //查询数据库数据
            QueryBuilder<Resource> resourceQueryBuilder = AppDatabase.getDaoSession().getResourceDao().queryBuilder();
            List<Resource> dbResourceList = resourceQueryBuilder.orderDesc(ResourceDao.Properties.ResCreateTime)
                    .offset(offset).limit(limit).list();
//            Collections.sort(dbResourceList);//时间排序 //IllegalArgumentException: Comparison method violates its general contract!
            emitter.onNext(Optional.ofNullable(dbResourceList));
            emitter.onComplete();
        });
    }


    /**
     * 获取本地资源 Observable
     * 通过时间段
     *
     * @param start
     * @param end
     * @return
     */
    private Observable<Optional<List<Resource>>> getLocalResourceListObservable(long start, long end) {
        return Observable.create((ObservableOnSubscribe<Optional<List<Resource>>>) emitter -> {
            //查询数据库数据
            QueryBuilder<Resource> resourceQueryBuilder = AppDatabase.getDaoSession().getResourceDao().queryBuilder();
            List<Resource> dbResourceList = resourceQueryBuilder.where(ResourceDao.Properties.ResCreateTime.between(start, end))
                    .orderDesc(ResourceDao.Properties.ResCreateTime).list();
//            Collections.sort(dbResourceList);//时间排序 //IllegalArgumentException: Comparison method violates its general contract!
            emitter.onNext(Optional.ofNullable(dbResourceList));
            emitter.onComplete();
        });
    }

    /**
     * 获取本地资源 Observable
     * 通过开始时间，限定数量
     *
     * @param start
     * @param limit
     * @return
     */
    private Observable<Optional<List<Resource>>> getLocalResourceListObservable(long start, int limit) {
        return Observable.create((ObservableOnSubscribe<Optional<List<Resource>>>) emitter -> {
            //查询数据库数据
            QueryBuilder<Resource> resourceQueryBuilder = AppDatabase.getDaoSession().getResourceDao().queryBuilder();
            List<Resource> dbResourceList = resourceQueryBuilder.whereOr(
                            ResourceDao.Properties.ResCreateTime.eq(start),
                            ResourceDao.Properties.ResCreateTime.le(start))
                    .orderDesc(ResourceDao.Properties.ResCreateTime).limit(limit).list();
//            Collections.sort(dbResourceList);//时间排序 //IllegalArgumentException: Comparison method violates its general contract!
            emitter.onNext(Optional.ofNullable(dbResourceList));
            emitter.onComplete();
        });
    }

    private void finishRefreshLayout(boolean noMoreData) {
        if (binding.srLayout.isRefreshing()) {
            if (noMoreData) {
                binding.srLayout.finishRefreshWithNoMoreData();
            } else {
                binding.srLayout.finishRefresh();
            }
        } else if (binding.srLayout.isLoading()) {
            if (noMoreData) {
                binding.srLayout.finishLoadMoreWithNoMoreData();
            } else {
                binding.srLayout.finishLoadMore();
            }
        }
    }

    @Override
    public int getLayoutId() {
        return R.layout.fragment_photo_list3;
    }
}
